Update split products from version 1.3.8 or earlier to 1.3.9

After discovering that the product split items for dimensional weight for some reason used a "weight fraction" for each piece of the item rather than the actual weight for each piece I decided it needed to be rewritten. While it makes sense to use a value fraction for the price of each piece of a split product, using a weight fraction just means a lot of extra work. The split product program must calculate an actual weight for each piece anyway before the packaging program can use it, and you have to know the actual weight of each piece before you can calculate the weight fraction, so why not just put in the actual piece weight directly and save the extra unneeded work.

I've updated the split product program to update the total product weight in the products table with the sum of the product pieces in the products_split table.

If you have not already installed split products the you need to be reading the split_products_instructions.txt file rather than this one. It has been updated with these changes.

To update the packaging split program requires the following steps:

1) Run the following SQL query on your database using phpMyAdmin or similar tool:

alter table products_split add products_weight decimal(5,2) not null;
update products_split ps join products p on p.products_id = ps.products_id set ps.products_weight = (ps.weight_fraction * p.products_weight);
alter table products_split drop weight_fraction;
ALTER TABLE  products_split CHANGE value_fraction value_fraction FLOAT(7, 5) NOT NULL DEFAULT  '0.50';

Don't worry about losing your weight data as I have included a line to calculate the weights for all split products before the weight_fraction is deleted.

2) In catalog/includes/classes/shopping_cart.php

Find the current function definition for get_products_for_packaging and REPLACE it with the following:

// get_products_for_packaging is a special function for split product support in the class packing
// assumes that you have added the sql for upsxml, which adds the table products_split
   function get_products_for_packaging() {
      if (!is_array($this->contents)) return false;
      $products_array = array();
      // get the list of product information
      $products = $this->get_products();
      // cycle through list
      foreach ($products as $product) {
        $split_query = tep_db_query("select * from " . TABLE_PRODUCTS_SPLIT . " where products_id = " . (int)$product['id']);
        // is this a split product?
        if (tep_db_num_rows($split_query) > 0) {
          // save the total prices of the split product
          $product_price = $product['price'];
          $product_final_price = $product['final_price'];
          while ($split_info = tep_db_fetch_array($split_query)) {
            // for each piece of the product replace only the information that is unique to the piece
            // other information from the product will remain unchanged
            $product['weight'] = $split_info['products_weight'];
            $product['length'] = $split_info['products_length'];
            $product['width'] = $split_info['products_width'];
            $product['height'] = $split_info['products_height'];
            $product['ready_to_ship'] = $split_info['products_ready_to_ship'];
            $product['price'] = round(($split_info['value_fraction'] * $product_price), 4);
            $product['final_price'] = round(($split_info['value_fraction'] * $product_final_price), 4);
            // save the updated product piece
            $products_array[] = $product;
          } // end while
        } else {
          // not a split product, save it directly
          $products_array[] = $product;
        }
      } // end foreach

      return $products_array;
   }

3) Replace the older split_product.php files with the new versions.

4) In admin/inludes/languages/english/categories.php

ADD the following before the closing ?>

  define('TEXT_READY_SHIP_EXPLAIN', '<small> Check if you can put a label on this product and ship it without additional packaging.</small>');
  define('TEXT_CANT_SPLIT_NEW_PRODUCT', 'New products must be saved to the database before they can be set as containing multiple boxes.');

5) In admin/categories.php

5a) Find the section for dimensional support entry that reads like this:

            <td class="main"><?php echo TEXT_PRODUCTS_READY_TO_SHIP; ?></td>
            <td class="main"><?php echo tep_draw_separator('pixel_trans.gif', '24', '15') . '&nbsp;' . tep_draw_checkbox_field('products_ready_to_ship', '1', (($product['products_ready_to_ship'] == '1') ? true : false)); ?></td>
          </tr>

and CHANGE it to read like this:

            <td class="main"><?php echo TEXT_PRODUCTS_READY_TO_SHIP; ?></td>
            <td class="main"><?php echo tep_draw_separator('pixel_trans.gif', '24', '15') . '&nbsp;' . tep_draw_checkbox_field('products_ready_to_ship', '1', (($product['products_ready_to_ship'] == '1') ? true : false)) . TEXT_READY_SHIP_EXPLAIN; ?></td>
          </tr>

5b) Find the section that was added after the entry for Ready To Ship that reads like this:

<?php
   if (isset($pInfo->products_id) && tep_not_null($pInfo->products_id)) {
?>
          <tr>
            <td class="main"><?php echo TEXT_PRODUCTS_SPLIT_PRODUCT; ?></td>
<?php $check_split_query = tep_db_query("select count(*) as total from " . TABLE_PRODUCTS_SPLIT . " where products_id = '" . $pInfo->products_id . "'");
      $check_split = tep_db_fetch_array($check_split_query);
?>
            <td class="main"><?php echo tep_draw_separator('pixel_trans.gif', '22', '15') . '&nbsp;' . ($check_split['total'] < 1 ? 'no' : $check_split['total']); ?>&nbsp;&nbsp;<?php echo '<a href="javascript:void(0)" onmouseover="window.status=\'' . TEXT_MOUSE_OVER_SPLIT_PRODUCTS . '\';return true;" onmouseout="window.status=\'\'; return true;" onclick="window.open(\'' . tep_href_link(FILENAME_SPLIT_PRODUCT, 'pid=' . $pInfo->products_id, 'NONSSL') . '\',\'' . NAME_WINDOW_SPLIT_PRODUCTS_POPUP . '\',\'menubar=yes,resizable=yes,scrollbars=yes,status=no,location=no,width=650,height=350\');return false">' . tep_image_button('button_edit.gif', IMAGE_UPDATE, 'style="vertical-align: middle;"'); ?></a></td>
          </tr>
<?php
  } // end if (isset($pInfo->products_id)) ...
?>

and CHANGE it to read like this:

<!-- // begin split products -->
          <tr>
            <td class="main"><?php echo TEXT_PRODUCTS_SPLIT_PRODUCT; ?></td>
<?php
   if (isset($pInfo->products_id) && tep_not_null($pInfo->products_id)) {
      $check_split_query = tep_db_query("select count(*) as total from " . TABLE_PRODUCTS_SPLIT . " where products_id = '" . (int)$pInfo->products_id . "'");
      $check_split = tep_db_fetch_array($check_split_query);
?>
            <td class="main"><?php echo tep_draw_separator('pixel_trans.gif', '22', '15') . '&nbsp;' . ($check_split['total'] < 1 ? 'no' : $check_split['total']); ?>&nbsp;&nbsp;<?php echo '<a href="javascript:void(0)" onmouseover="window.status=\'' . TEXT_MOUSE_OVER_SPLIT_PRODUCTS . '\';return true;" onmouseout="window.status=\'\'; return true;" onclick="window.open(\'' . tep_href_link(FILENAME_SPLIT_PRODUCT, 'pid=' . $pInfo->products_id, 'NONSSL') . '\',\'' . NAME_WINDOW_SPLIT_PRODUCTS_POPUP . '\',\'menubar=yes,resizable=yes,scrollbars=yes,status=no,location=no,width=650,height=350\');return false">' . tep_image_button('button_edit.gif', IMAGE_UPDATE, 'style="vertical-align: middle;"'); ?></a></td>
          </tr>
<?php
  } else {
    echo '<td class="main">' . TEXT_CANT_SPLIT_NEW_PRODUCT . "</td></tr>\n";
  } // end split products
?>

5c) Near the end of the file find the section that reads:

          } elseif (isset($pInfo) && is_object($pInfo)) { // product info box contents
            $heading[] = array('text' => '<b>' . tep_get_products_name($pInfo->products_id, $languages_id) . '</b>');

            $contents[] = array('align' => 'center', 'text' => '<a href="' . tep_href_link(FILENAME_CATEGORIES, 'cPath=' . $cPath . '&pID=' . $pInfo->products_id . '&action=new_product') . '">' . tep_image_button('button_edit.gif', IMAGE_EDIT) . '</a> <a href="' . tep_href_link(FILENAME_CATEGORIES, 'cPath=' . $cPath . '&pID=' . $pInfo->products_id . '&action=delete_product') . '">' . tep_image_button('button_delete.gif', IMAGE_DELETE) . '</a> <a href="' . tep_href_link(FILENAME_CATEGORIES, 'cPath=' . $cPath . '&pID=' . $pInfo->products_id . '&action=move_product') . '">' . tep_image_button('button_move.gif', IMAGE_MOVE) . '</a> <a href="' . tep_href_link(FILENAME_CATEGORIES, 'cPath=' . $cPath . '&pID=' . $pInfo->products_id . '&action=copy_to') . '">' . tep_image_button('button_copy_to.gif', IMAGE_COPY_TO) . '</a>');


and AFTER it ADD the following:

            $contents[] = array('align' => 'center', 'text' => '<form name="edit_splits" action="" method="post">' . tep_draw_input_field('split', TEXT_PRODUCTS_SPLIT_PRODUCT, 'alt="' . TEXT_PRODUCTS_SPLIT_PRODUCT . '" onmouseover="window.status=\'' . TEXT_MOUSE_OVER_SPLIT_PRODUCTS . '\';return true;" onmouseout="window.status=\'\'; return true;" onclick="javascript:window.open(\'' . tep_href_link(FILENAME_SPLIT_PRODUCT, 'pid=' . $pInfo->products_id, 'NONSSL') . '\',\'' . NAME_WINDOW_SPLIT_PRODUCTS_POPUP . '\',\'menubar=yes,resizable=yes,scrollbars=yes,status=no,location=no,width=650,height=350\')"', false, 'submit') . '</form>');

5d) Near the top of the file underneath:

      case 'insert_product':
      case 'update_product':

Find this section:

          $sql_data_array = array('products_quantity' => (int)tep_db_prepare_input($HTTP_POST_VARS['products_quantity']),
                                  'products_model' => tep_db_prepare_input($HTTP_POST_VARS['products_model']),
                                  'image_display' => tep_db_prepare_input($HTTP_POST_VARS['image_display']),
                                  'products_price' => tep_db_prepare_input($HTTP_POST_VARS['products_price']),
                                  'products_date_available' => $products_date_available,
                                  'products_weight' => (float)tep_db_prepare_input($HTTP_POST_VARS['products_weight']),
                                  'products_height' => tep_db_prepare_input($HTTP_POST_VARS['products_height']),
                                  'products_length' => tep_db_prepare_input($HTTP_POST_VARS['products_length']),
                                  'products_width' => tep_db_prepare_input($HTTP_POST_VARS['products_width']),
                                  'products_ready_to_ship' => tep_db_prepare_input($HTTP_POST_VARS['products_ready_to_ship']),
                                  'products_status' => tep_db_prepare_input($HTTP_POST_VARS['products_status']),
                                  'products_tax_class_id' => tep_db_prepare_input($HTTP_POST_VARS['products_tax_class_id']),
                                  'manufacturers_id' => (int)tep_db_prepare_input($HTTP_POST_VARS['manufacturers_id']));


and CHANGE it to read as follows:

          $sql_data_array = array('products_quantity' => (int)tep_db_prepare_input($HTTP_POST_VARS['products_quantity']),
                                  'products_model' => tep_db_prepare_input($HTTP_POST_VARS['products_model']),
                                  'image_display' => tep_db_prepare_input($HTTP_POST_VARS['image_display']),
                                  'products_price' => tep_db_prepare_input($HTTP_POST_VARS['products_price']),
                                  'products_date_available' => $products_date_available,
                                  'products_height' => tep_db_prepare_input($HTTP_POST_VARS['products_height']),
                                  'products_length' => tep_db_prepare_input($HTTP_POST_VARS['products_length']),
                                  'products_width' => tep_db_prepare_input($HTTP_POST_VARS['products_width']),
                                  'products_ready_to_ship' => tep_db_prepare_input($HTTP_POST_VARS['products_ready_to_ship']),
                                  'products_status' => tep_db_prepare_input($HTTP_POST_VARS['products_status']),
                                  'products_tax_class_id' => tep_db_prepare_input($HTTP_POST_VARS['products_tax_class_id']),
                                  'manufacturers_id' => (int)tep_db_prepare_input($HTTP_POST_VARS['manufacturers_id']));
          if (isset($HTTP_GET_VARS['pID'])) {
            $split_check_query = tep_db_query("select count(*) as total from " . TABLE_PRODUCTS_SPLIT . " where products_id = '" . (int)$HTTP_GET_VARS['pID'] . "'");
            $check_split = tep_db_fetch_array($split_check_query);
            $split_product = ($check_split['total'] > 0);
          } else {
            $split_product = false;
          }
          if (!$split_product) // if not a split product save the weight, otherwise it will be calculated from the split
            $sql_data_array['products_weight'] = (float)tep_db_prepare_input($HTTP_POST_VARS['products_weight']);


5e) Scroll down and find the following section:

          } elseif ($HTTP_POST_VARS['copy_as'] == 'duplicate') {
            $product_query = tep_db_query("select products_quantity, products_model, products_image, products_price, products_date_available, products_weight, products_length, products_width, products_height, products_ready_to_ship, products_tax_class_id, manufacturers_id from " . TABLE_PRODUCTS . " where products_id = '" . (int)$products_id . "'");
            $product = tep_db_fetch_array($product_query);

            tep_db_query("insert into " . TABLE_PRODUCTS . " (products_quantity, products_model, products_image, products_price, products_date_added, products_date_available, products_weight, products_length, products_width, products_height, products_ready_to_ship, products_status, products_tax_class_id, manufacturers_id) values ('" . tep_db_input($product['products_quantity']) . "', '" . tep_db_input($product['products_model']) . "', '" . tep_db_input($product['products_image']) . "', '" . tep_db_input($product['products_price']) . "',  now(), " . (empty($product['products_date_available']) ? "null" : "'" . tep_db_input($product['products_date_available']) . "'") . ", '" . tep_db_input($product['products_weight']) . "', '" . tep_db_input($product['products_length']) . "', '" . tep_db_input($product['products_width']) . "', '" . tep_db_input($product['products_height']) . "', '" . tep_db_input($product['products_ready_to_ship']) . "', '0', '" . (int)$product['products_tax_class_id'] . "', '" . (int)$product['manufacturers_id'] . "')");
            $dup_products_id = tep_db_insert_id();

and ADD AFTER it:

            // begin split products
            $split_query = tep_db_query('select * from ' . TABLE_PRODUCTS_SPLIT . ' where products_id = ' . (int)$products_id);
            while ($item = tep_db_fetch_array($split_query)) {
              tep_db_query('insert into ' . TABLE_PRODUCTS_SPLIT . " (products_id, products_weight, products_length, products_width, products_height, products_ready_to_ship, value_fraction) VALUES ('" . (int)$dup_products_id . "', '" . tep_db_input($item['products_weight']) . "', '" . tep_db_input($item['products_length']) . "', '" . tep_db_input($item['products_width']) . "', '" . tep_db_input($item['products_height']) . "', '" . tep_db_input($item['products_ready_to_ship']) . "', '" . tep_db_input($item['value_fraction']) . "')");
            }
            // end split products

6) In admin/includes/functions/general.php

Find the function definition for tep_remove_product

In that definition find the section that reads:

    tep_db_query("delete from " . TABLE_SPECIALS . " where products_id = '" . (int)$product_id . "'");
    tep_db_query("delete from " . TABLE_PRODUCTS . " where products_id = '" . (int)$product_id . "'");
    tep_db_query("delete from " . TABLE_PRODUCTS_TO_CATEGORIES . " where products_id = '" . (int)$product_id . "'");
    tep_db_query("delete from " . TABLE_PRODUCTS_TO_NOTES . " where products_id = '" . (int)$product_id . "'");
    tep_db_query("delete from " . TABLE_PRODUCTS_DESCRIPTION . " where products_id = '" . (int)$product_id . "'");
    tep_db_query("delete from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . (int)$product_id . "'");
    tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where products_id = '" . (int)$product_id . "' or products_id like '" . (int)$product_id . "{%'");
    tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where products_id = '" . (int)$product_id . "' or products_id like '" . (int)$product_id . "{%'");

and immediately below it ADD:

    tep_db_query("delete from " . TABLE_PRODUCTS_SPLIT . " where products_id = '" . (int)$product_id . "'");
